/**
 * 
 * Copyright (C) 2011 Cody Stoutenburg . All rights reserved.
 *
 *       This program is free software; you can redistribute it and/or
 *       modify it under the terms of the GNU Lesser General Public License
 *       as published by the Free Software Foundation; either version 2.1
 *       of the License, or (at your option) any later version.
 *
 *       This program is distributed in the hope that it will be useful,
 *       but WITHOUT ANY WARRANTY; without even the implied warranty of
 *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *       GNU Lesser General Public License for more details.
 *
 *       You should have received a copy of the GNU Lesser General Public License
 *       along with this program; if not, write to the Free Software
 *       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 * 
 */
package ca.usherbrooke.model.world;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.newdawn.slick.geom.Rectangle;

import ca.usherbrooke.model.entity.IEntityGame;
import ca.usherbrooke.model.feature.FeatureModel;
import ca.usherbrooke.model.feature.GroundModel;
import ca.usherbrooke.model.feature.WallModel;
import ca.usherbrooke.tools.position.Vector2D;

/**
 * this class represent a basic world that contains only grounds and wall
 * 
 * @author Cody Stoutenburg
 * 
 */
public class BasicWorldModel implements Serializable {
	private static final long serialVersionUID = 1L;

	protected Long realTimeElapse;
	protected final Rectangle size;
	protected final Integer blockSize;

	// all elements on map
	protected FeatureModel[][] allGrounds;

	public BasicWorldModel(Integer blockSize, Integer x, Integer y,
			Integer width, Integer height) {
		size = new Rectangle(x, y, width, height);
		this.blockSize = blockSize;
		allGrounds = new FeatureModel[(x + width) / blockSize][(y + height)
				/ blockSize];

		realTimeElapse = 0L;
	}

	protected final class Pair<E1, E2> {
		public E1 first;
		public E2 second;
	}

	protected Pair<Integer, Integer> positionToIdx(Vector2D position) {
		return positionToIdx(position.getX(), position.getY());
	}

	protected Pair<Integer, Integer> positionToIdx(float x, float y) {
		Pair<Integer, Integer> idx = new Pair<Integer, Integer>();

		int xPos = (int) Math.floor(x / blockSize);
		int yPos = (int) Math.floor(y / blockSize);

		xPos = Math.max(xPos, 0);
		yPos = Math.max(yPos, 0);
		xPos = Math.min(xPos, getTileWidth() - 1);
		yPos = Math.min(yPos, getTileHeight() - 1);

		idx.first = xPos;
		idx.second = yPos;

		return idx;
	}

	public final FeatureModel getTileAt(int x, int y) {
		return allGrounds[x][y];
	}

	public final int getTileWidth() {
		return allGrounds.length;
	}

	public final int getTileHeight() {
		return allGrounds[0].length;
	}

	public final Rectangle getSize() {
		return this.size;
	}

	public final Float getWidth() {
		return size.getWidth();
	}

	public final Float getHeight() {
		return size.getHeight();
	}

	public final Long getRealTimeElapse() {
		return this.realTimeElapse;
	}

	protected final void addFeatureModel(int x, int y, FeatureModel ground) {
		this.allGrounds[x][y] = ground;
	}

	protected final void removeFeatureModel(Vector2D position) {
		Pair<Integer, Integer> idx = positionToIdx(position);
		this.allGrounds[idx.first][idx.second] = null;
	}

	public void addGround(int x, int y, GroundModel ground) {
		addFeatureModel(x, y, ground);
	}

	public void removeGround(Vector2D position) {
		if (getGround(position) != null) {
			this.removeFeatureModel(position);
		}
	}

	public void addWall(int x, int y, WallModel wall) {
		addFeatureModel(x, y, wall);
	}

	public void removeWall(Vector2D position) {
		if (getWall(position) != null) {
			this.removeFeatureModel(position);
		}
	}

	protected void setGroundForEntity(IEntityGame entity) {
		GroundModel ground = this.getGround(entity.getCenterPosition());
		entity.setWalkOn(ground);
	}

	protected FeatureModel getGrounds(Vector2D position) {
		Pair<Integer, Integer> idx = positionToIdx(position);

		return allGrounds[idx.first][idx.second];
	}

	protected List<FeatureModel> getGrounds(Rectangle position) {
		List<FeatureModel> result = new ArrayList<FeatureModel>();

		Pair<Integer, Integer> idxMin = positionToIdx(position.getMinX(),
				position.getMinY());

		Pair<Integer, Integer> idxMax = positionToIdx(position.getMaxX(),
				position.getMaxY());

		for (int i = idxMin.first; i <= idxMax.first; ++i) {
			for (int j = idxMin.second; j <= idxMax.second; ++j) {
				if (allGrounds[i][j] != null) {
					result.add(allGrounds[i][j]);
				}
			}
		}

		return result;
	}

	public GroundModel getGround(Vector2D position) {
		FeatureModel model = getGrounds(position);
		GroundModel ground = null;
		if (model != null && model instanceof GroundModel) {
			ground = (GroundModel) model;
		}
		return ground;
	}

	public WallModel getWall(Vector2D position) {
		FeatureModel model = getGrounds(position);
		WallModel wall = null;
		if (model != null && model instanceof WallModel) {
			wall = (WallModel) model;
		}
		return wall;
	}

	public List<WallModel> getWall(Rectangle position) {
		List<FeatureModel> grounds = getGrounds(position);
		List<WallModel> result = new ArrayList<WallModel>();

		for (FeatureModel ground : grounds) {
			if (ground instanceof WallModel) {
				result.add((WallModel) ground);
			}
		}

		return result;
	}
}
